home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sun Solutions 2000 #3
/
Sun Solutions CD Volume 3, 2003 (704-7473-10 Rev. J)(Sun Microsystems, Inc.)(2003).iso
/
products
/
SunSolutions
/
classes
/
imagemap.java
< prev
next >
Wrap
Text File
|
2003-07-14
|
32KB
|
1,179 lines
import java.applet.Applet;
import java.awt.Image;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Hashtable;
import java.net.URL;
import java.awt.image.*;
import java.net.MalformedURLException;
/**
* An extensible ImageMap applet class.
* The active areas on the image are controlled by ImageArea classes
* that can be dynamically loaded over the net.
*
* @author Jim Graham
* @version %I%, %G%
*/
public class ImageMap extends Applet {
/**
* The unhighlighted image being mapped.
*/
Image baseImage;
/**
* The list of image area handling objects;
*/
ImageMapArea areas[];
/**
* The primary highlight mode to be used.
*/
static final int BRIGHTER = 0;
static final int DARKER = 1;
int hlmode = BRIGHTER;
/**
* The percentage of highlight to apply for the primary highlight mode.
*/
int hlpercent = 50;
/**
* Get a rectangular region of the baseImage highlighted according to
* the primary highlight specification.
*/
Image getHighlight(int x, int y, int w, int h) {
return getHighlight(x, y, w, h, hlmode, hlpercent);
}
/**
* Get a rectangular region of the baseImage with a specific highlight.
*/
Image getHighlight(int x, int y, int w, int h, int mode, int percent) {
return getHighlight(x, y, w, h, new HighlightFilter(mode == BRIGHTER,
percent));
}
/**
* Get a rectangular region of the baseImage modified by an image filter.
*/
Image getHighlight(int x, int y, int w, int h, ImageFilter filter) {
Image cropped = makeImage(baseImage, new CropImageFilter(x, y, w, h));
return makeImage(cropped, filter);
}
/**
* Make the primary highlighted version of the baseImage.
*/
Image makeImage(Image orig, ImageFilter filter) {
return createImage(new FilteredImageSource(orig.getSource(), filter));
}
/**
* Parse a string representing the desired highlight to be applied.
*/
void parseHighlight(String s) {
if (s == null) {
return;
}
if (s.startsWith("brighter")) {
hlmode = BRIGHTER;
if (s.length() > "brighter".length()) {
hlpercent = Integer.parseInt(s.substring("brighter".length()));
}
} else if (s.startsWith("darker")) {
hlmode = DARKER;
if (s.length() > "darker".length()) {
hlpercent = Integer.parseInt(s.substring("darker".length()));
}
}
}
/**
* Initialize the applet. Get attributes.
*
* Initialize the ImageAreas.
* Each ImageArea is a subclass of the class ImageArea, and is
* specified with an attribute of the form:
* areaN=ImageAreaClassName,arguments...
* The ImageAreaClassName is parsed off and a new instance of that
* class is created. The initializer for that class is passed a
* reference to the applet and the remainder of the attribute
* string, from which the class should retrieve any information it
* needs about the area it controls and the actions it needs to
* take within that area.
*/
public void init() {
String s;
parseHighlight(getParameter("highlight"));
baseImage = getImage(getDocumentBase(), getParameter("img"));
Vector areaVec = new Vector();
int num = 1;
while (true) {
ImageMapArea newArea;
s = getParameter("area"+num);
if (s == null) {
// Try rect for backwards compatibility.
s = getParameter("rect"+num);
if (s == null) {
break;
}
String url = getParameter("href"+num);
if (url != null)
s += "," + url;
newArea = new HrefArea();
} else {
int classend = s.indexOf(",");
try {
String name = s.substring(0, classend);
newArea = (ImageMapArea) Class.forName(name).newInstance();
} catch (Exception e) {
e.printStackTrace();
break;
}
s = s.substring(classend+1);
}
newArea.init(this, s);
areaVec.addElement(newArea);
num++;
}
areas = new ImageMapArea[areaVec.size()];
areaVec.copyInto(areas);
checkSize();
}
/**
* Check the size of this applet while the image is being loaded.
*/
synchronized void checkSize() {
int w = baseImage.getWidth(this);
int h = baseImage.getHeight(this);
if (w > 0 && h > 0) {
resize(w, h);
repaintrect.x = repaintrect.y = 0;
repaintrect.width = w;
repaintrect.height = h;
fullrepaint = true;
repaint();
}
}
private boolean fullrepaint = false;
private Rectangle repaintrect = new Rectangle();
private long lastupdate = 0;
private final static long UPDATERATE = 100;
/**
* Handle updates from images being loaded.
*/
public boolean imageUpdate(Image img, int infoflags,
int x, int y, int width, int height) {
if ((infoflags & (WIDTH | HEIGHT)) != 0) {
checkSize();
}
if ((infoflags & (SOMEBITS | FRAMEBITS | ALLBITS)) != 0) {
repaint(((infoflags & (FRAMEBITS | ALLBITS)) != 0)
? 0 : UPDATERATE,
x, y, width, height);
}
return (infoflags & (ALLBITS | ERROR)) == 0;
}
/**
* Paint the image and all active highlights.
*/
public void paint(Graphics g) {
synchronized(this) {
if (fullrepaint) {
g = g.create();
g.clipRect(repaintrect.x, repaintrect.y,
repaintrect.width, repaintrect.height);
fullrepaint = false;
}
}
if (baseImage == null) {
return;
}
g.drawImage(baseImage, 0, 0, this);
if (areas != null) {
for (int i = areas.length; --i >= 0; ) {
if (areas[i].active || areas[i].entered) {
areas[i].setState(g, areas[i].entered);
}
}
}
}
/**
* Update the active highlights on the image.
*/
public void update(Graphics g) {
if (fullrepaint) {
paint(g);
return;
}
if (baseImage == null) {
return;
}
g.drawImage(baseImage, 0, 0, this);
if (areas == null) {
return;
}
// First unhighlight all of the deactivated areas
for (int i = areas.length; --i >= 0; ) {
if (areas[i].active && !areas[i].entered) {
areas[i].setState(g, false);
}
}
// Then highlight all of the activated areas
for (int i = areas.length; --i >= 0; ) {
if (areas[i].entered) {
areas[i].setState(g, true);
}
}
}
/**
* Make sure that no ImageAreas are highlighted.
*/
public void mouseExit() {
boolean changed = false;
for (int i = 0; i < areas.length; i++) {
if (areas[i].active) {
areas[i].entered = false;
changed = true;
}
}
if (changed) {
repaint();
}
}
/**
* Find the ImageAreas that the mouse is in.
*/
public boolean mouseMove(java.awt.Event evt, int x, int y) {
boolean changed = false;
boolean propagate = true;
for (int i = 0; i < areas.length; i++) {
if (areas[i].inside(x, y)) {
areas[i].entered = propagate;
if (areas[i].terminal) {
propagate = false;
}
} else {
areas[i].entered = false;
}
if (areas[i].active != areas[i].entered) {
changed = true;
}
}
if (changed) {
repaint();
}
return true;
}
int pressX;
int pressY;
/**
* Inform all active ImageAreas of a mouse press.
*/
public boolean mouseDown(java.awt.Event evt, int x, int y) {
pressX = x;
pressY = y;
for (int i = 0; i < areas.length; i++) {
if (areas[i].inside(x, y)) {
areas[i].press(x, y);
if (areas[i].terminal) {
break;
}
}
}
return true;
}
/**
* Inform all active ImageAreas of a mouse release.
* Only those areas that were inside the original mouseDown()
* are informed of the mouseUp.
*/
public boolean mouseUp(java.awt.Event evt, int x, int y) {
for (int i = 0; i < areas.length; i++) {
if (areas[i].inside(pressX, pressY)) {
areas[i].lift(x, y);
if (areas[i].terminal) {
break;
}
}
}
return true;
}
/**
* Inform all active ImageAreas of a mouse drag.
* Only those areas that were inside the original mouseDown()
* are informed of the mouseUp.
*/
public boolean mouseDrag(java.awt.Event evt, int x, int y) {
mouseMove(evt, x, y);
for (int i = 0; i < areas.length; i++) {
if (areas[i].inside(pressX, pressY)) {
areas[i].drag(x, y);
if (areas[i].terminal) {
break;
}
}
}
return true;
}
}
/**
* The base ImageArea class.
* This class performs the basic functions that most ImageArea
* classes will need and delegates specific actions to the subclasses.
*
* @author Jim Graham
* @version %I%, %G%
*/
class ImageMapArea implements ImageObserver {
/** The applet parent that contains this ImageArea. */
ImageMap parent;
/** The X location of the area (if rectangular). */
int X;
/** The Y location of the area (if rectangular). */
int Y;
/** The size().width of the area (if rectangular). */
int W;
/** The size().height of the area (if rectangular). */
int H;
/**
* This flag indicates whether the user was in this area during the
* last scan of mouse locations.
*/
boolean entered = false;
/** This flag indicates whether the area is currently highlighted. */
boolean active = false;
/**
* This flag indicates whether the area is terminal. Terminal areas
* prevent any areas which are under them from being activated when
* the mouse is inside them. Some areas may wish to change this to
* false so that they can augment other areas that they are on top of.
*/
boolean terminal = true;
/**
* This is the default highlight image if no special effects are
* needed to draw the highlighted image. It is created by the
* default "makeImages()" method.
*/
Image hlImage;
/**
* Initialize this ImageArea as called from the applet.
* If the subclass does not override this initializer, then it
* will perform the basic functions of setting the parent applet
* and parsing out 4 numbers from the argument string which specify
* a rectangular region for the ImageArea to act on.
* The remainder of the argument string is passed to the handleArg()
* method for more specific handling by the subclass.
*/
public void init(ImageMap parent, String args) {
this.parent = parent;
StringTokenizer st = new StringTokenizer(args, ", ");
X = Integer.parseInt(st.nextToken());
Y = Integer.parseInt(st.nextToken());
W = Integer.parseInt(st.nextToken());
H = Integer.parseInt(st.nextToken());
if (st.hasMoreTokens()) {
// hasMoreTokens() Skips the trailing comma
handleArg(st.nextToken(""));
} else {
handleArg(null);
}
makeImages();
}
/**
* This method handles the remainder of the argument string after
* the standard initializer has parsed off the 4 rectangular
* parameters. If the subclass does not override this method,
* the remainder will be ignored.
*/
public void handleArg(String s) {
}
/**
* This method sets the image to be used to render the ImageArea
* when it is highlighted.
*/
public void setHighlight(Image img) {
hlImage = img;
}
/**
* This method handles the construction of the various images
* used to highlight this particular ImageArea when the user
* interacts with it.
*/
public void makeImages() {
setHighlight(parent.getHighlight(X, Y, W, H));
}
/**
* This method tests to see if a point is inside this ImageArea.
* The standard method assumes a rectangular area as parsed by
* the standard initializer. If a more complex area is required
* then this method will have to be overridden by the subclass.
*/
public boolean inside(int x, int y) {
return (x >= X && x < (X + W) && y >= Y && y < (Y + H));
}
/**
* This utility method draws a rectangular subset of a highlight
* image.
*/
public void drawImage(Graphics g, Image img, int imgx, int imgy,
int x, int y, int w, int h) {
Graphics ng = g.create();
ng.clipRect(x, y, w, h);
ng.drawImage(img, imgx, imgy, this);
}
/**
* This method handles the updates from drawing the images.
*/
public boolean imageUpdate(Image img, int infoflags,
int x, int y, int width, int height) {
if (img == hlImage) {
return parent.imageUpdate(img, infoflags, x + X, y + Y,
width, height);
} else {
return false;
}
}
/**
* This utility method shows a string in the status bar.
*/
public void showStatus(String msg) {
parent.getAppletContext().showStatus(msg);
}
/**
* This utility method tells the browser to visit a URL.
*/
public void showDocument(URL u) {
parent.getAppletContext().showDocument(u);
}
/**
* This method highlights the specified area when the user enters
* it with his mouse. The standard highlight method is to replace
* the indicated rectangular area of the image with the primary
* highlighted image.
*/
public void highlight(Graphics g, boolean on) {
if (on) {
g.drawImage(hlImage, X, Y, this);
} else {
drawImage(g, parent.baseImage, 0, 0, X, Y, W, H);
}
}
/**
* This method changes the active state of the ImageArea, which
* indicates whether the user is currently "inside" this area.
* It turns around and calls the highlight method which is likely
* to have been overridden by subclasses seeking a custom highlight.
*/
public void setState(Graphics g, boolean on) {
highlight(g, on);
active = on;
}
/**
* The press method is called when the user presses the mouse
* button inside the ImageArea. The location is supplied, but
* the standard implementation is to call the overloaded method
* with no arguments.
*/
public void press(int x, int y) {
press();
}
/**
* The overloaded press method is called when the user presses the
* mouse button inside the ImageArea. This method can be overridden
* if the ImageArea does not need to know the location of the press.
*/
public void press() {
}
/**
* The lift method is called when the user releases the mouse button.
* The location is supplied, but the standard implementation is to
* call the overloaded method with no arguments. Only those ImageAreas
* that were informed of a press will be informed of the corresponding
* release.
*/
public void lift(int x, int y) {
lift();
}
/**
* The overloaded lift method is called when the user releases the
* mouse button. This method can be overridden if the ImageArea
* does not need to know the location of the release.
*/
public void lift() {
}
/**
* The drag method is called when the user moves the mouse while
* the button is pressed. Only those ImageAreas that were informed
* of a press will be informed of the corresponding mouse movements.
*/
public void drag(int x, int y) {
}
}
/**
* The classic "Fetch a URL" ImageArea class.
* This class extends the basic ImageArea Class to fetch a URL when
* the user clicks in the area.
*
* @author Jim Graham
* @version %I%, %G%
*/
class HrefArea extends ImageMapArea {
/** The URL to be fetched when the user clicks on this area. */
URL anchor;
/**
* The argument string is the URL to be fetched.
*/
public void handleArg(String arg) {
try {
anchor = new URL(parent.getDocumentBase(), arg);
} catch (MalformedURLException e) {
anchor = null;
}
}
/**
* The status message area is updated to show the destination URL.
* The default graphics highlight feedback is used.
*/
public void highlight(Graphics g, boolean on) {
super.highlight(g, on);
showStatus((on && anchor != null)
? "Go To " + anchor.toExternalForm()
: null);
}
/**
* The new URL is fetched when the user releases the mouse button
* only if they are still in the area.
*/
public void lift(int x, int y) {
if (inside(x, y) && anchor != null) {
showDocument(anchor);
}
// Note that we should not be active, so no repaint is necessary.
}
}
/**
* An audio feedback ImageArea class.
* This class extends the basic ImageArea Class to play a sound each
* time the user enters the area.
*
* @author Jim Graham
* @version %I%, %G%
*/
class SoundArea extends ImageMapArea {
/** The URL of the sound to be played. */
String sound;
/**
* The argument is the URL of the sound to be played.
* This method also sets this type of area to be non-terminal.
*/
public void handleArg(String arg) {
sound = arg;
terminal = false;
}
/**
* The highlight method plays the sound in addition to the usual
* graphical highlight feedback.
*/
public void highlight(Graphics g, boolean on) {
if (on && !active) {
parent.play(parent.getDocumentBase(), sound);
}
super.highlight(g, on);
}
}
/**
* An click feedback ImageArea class.
* This class extends the basic ImageArea Class to show the locations
* of clicks in the image in the status message area. This utility
* ImageArea class is useful when setting up ImageMaps.
*
* @author Jim Graham
* @version %I%, %G%
*/
class ClickArea extends ImageMapArea {
/** The X location of the last mouse press. */
int startx;
/** The Y location of the last mouse press. */
int starty;
/**
* The argument is ignored, but we use this method to set this type
* of area to be non-terminal.
*/
public void handleArg(String arg) {
terminal = false;
}
/** This class overrides the highlight method to prevent highlighting. */
public void highlight(Graphics g, boolean on) {
}
String ptstr(int x, int y) {
return "("+x+", "+y+")";
}
/**
* When the user presses the mouse button, start showing coordinate
* feedback in the status message line.
*/
public void press(int x, int y) {
showStatus("Clicked at "+ptstr(x, y));
startx = x;
starty = y;
}
/**
* Update the coordinate feedback every time the user moves the mouse
* while he has the button pressed.
*/
public void drag(int x, int y) {
showStatus("Rectangle from "+ptstr(startx, starty)
+" to "+ptstr(x, y)
+" is "+(x-startx)+"x"+(y-starty));
}
/**
* Update the coordinate feedback one last time when the user releases
* the mouse button.
*/
public void lift(int x, int y) {
drag(x, y);
}
}
/**
* A message feedback ImageArea class.
* This class extends the basic ImageArea Class to show the a given
* message in the status message area when the user enters this area.
*
* @author Jim Graham
* @version %I%, %G%
*/
class NameArea extends ImageMapArea {
/** The string to be shown in the status message area. */
String name;
/**
* The argument is the string to be displayed in the status message
* area. This method also sets this type of area to be non-terminal.
*/
public void handleArg(String arg) {
name = arg;
terminal = false;
}
/**
* The highlight method displays the message in addition to the usual
* graphical highlight feedback.
*/
public void highlight(Graphics g, boolean on) {
super.highlight(g, on);
showStatus(on ? name : null);
}
}
/**
* An improved "Fetch a URL" ImageArea class.
* This class extends the basic ImageArea Class to fetch a URL when
* the user clicks in the area. In addition, special custom highlights
* are used to make the area look and feel like a 3-D button.
*
* @author Jim Graham
* @version %I%, %G%
*/
class HrefButtonArea extends ImageMapArea {
/** The URL to be fetched when the user clicks on this area. */
URL anchor;
/** The highlight image for when the button is "UP". */
Image upImage;
/** The highlight image for when the button is "DOWN". */
Image downImage;
/** This flag indicates if the "button" is currently pressed. */
boolean pressed = false;
/** The border size for the 3-D effect. */
int border = 5;
/**
* The argument string is the URL to be fetched.
* This method also constructs the various highlight images needed
* to achieve the 3-D effect.
*/
public void handleArg(String arg) {
try {
anchor = new URL(parent.getDocumentBase(), arg);
} catch (MalformedURLException e) {
anchor = null;
}
if (border * 2 > W || border * 2 > H) {
border = Math.min(W, H) / 2;
}
}
public void makeImages() {
upImage = parent.getHighlight(X, Y, W, H,
new ButtonFilter(false,
parent.hlpercent,
border, W, H));
downImage = parent.getHighlight(X, Y, W, H,
new ButtonFilter(true,
parent.hlpercent,
border, W, H));
}
public boolean imageUpdate(Image img, int infoflags,
int x, int y, int width, int height) {
if (img == (pressed ? downImage : upImage)) {
return parent.imageUpdate(img, infoflags, x + X, y + Y,
width, height);
} else {
return (img == downImage || img == upImage);
}
}
/**
* The status message area is updated to show the destination URL.
* The graphical highlight is achieved using the ButtonFilter.
*/
public void highlight(Graphics g, boolean on) {
if (on) {
setHighlight(pressed ? downImage : upImage);
}
super.highlight(g, on);
showStatus((on && anchor != null)
? "Go To " + anchor.toExternalForm()
: null);
}
/**
* Since the highlight changes when the button is pressed, we need
* to record the "pressed" state and induce a repaint.
*/
public void press() {
parent.repaint();
pressed = true;
}
/**
* The new URL is fetched when the user releases the mouse button
* only if they are still in the area.
*/
public void lift(int x, int y) {
pressed = false;
parent.repaint();
if (inside(x, y) && anchor != null) {
showDocument(anchor);
}
}
}
/**
* An improved, round, "Fetch a URL" ImageArea class.
* This class extends the HrefButtonArea Class to make the 3D button
* a rounded ellipse. All of the same feedback and operational
* charactistics as the HrefButtonArea apply.
*
* @author Jim Graham
* @version %I%, %G%
*/
class RoundHrefButtonArea extends HrefButtonArea {
public void makeImages() {
upImage = parent.getHighlight(X, Y, W, H,
new RoundButtonFilter(false,
parent.hlpercent,
border, W, H));
downImage = parent.getHighlight(X, Y, W, H,
new RoundButtonFilter(true,
parent.hlpercent,
border, W, H));
}
}
class HighlightFilter extends RGBImageFilter {
boolean brighter;
int percent;
public HighlightFilter(boolean b, int p) {
brighter = b;
percent = p;
canFilterIndexColorModel = true;
}
public int filterRGB(int x, int y, int rgb) {
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb >> 0) & 0xff;
if (brighter) {
r = (255 - ((255 - r) * (100 - percent) / 100));
g = (255 - ((255 - g) * (100 - percent) / 100));
b = (255 - ((255 - b) * (100 - percent) / 100));
} else {
r = (r * (100 - percent) / 100);
g = (g * (100 - percent) / 100);
b = (b * (100 - percent) / 100);
}
if (r < 0) r = 0;
if (r > 255) r = 255;
if (g < 0) g = 0;
if (g > 255) g = 255;
if (b < 0) b = 0;
if (b > 255) b = 255;
return (rgb & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
}
}
class ButtonFilter extends RGBImageFilter {
boolean pressed;
int defpercent;
int border;
int width;
int height;
ColorModel models[] = new ColorModel[7];
ColorModel origbuttonmodel;
public ButtonFilter(boolean press, int p, int b, int w, int h) {
pressed = press;
defpercent = p;
border = b;
width = w;
height = h;
}
public void setHints(int hints) {
super.setHints(hints & (~ImageConsumer.COMPLETESCANLINES));
}
public void setColorModel(ColorModel model) {
if (model instanceof IndexColorModel && true) {
IndexColorModel icm = (IndexColorModel) model;
models[0] = filterIndexColorModel(icm, false, false, 0);
models[1] = filterIndexColorModel(icm, true, !pressed, defpercent);
models[2] = null;
if (pressed) {
models[3] = filterIndexColorModel(icm, true, false,
defpercent/2);
} else {
models[3] = models[0];
}
models[4] = null;
models[5] = filterIndexColorModel(icm, true, pressed, defpercent);
models[6] = models[0];
origbuttonmodel = model;
consumer.setColorModel(models[3]);
} else {
super.setColorModel(model);
}
}
public IndexColorModel filterIndexColorModel(IndexColorModel icm,
boolean opaque,
boolean brighter,
int percent) {
byte r[] = new byte[256];
byte g[] = new byte[256];
byte b[] = new byte[256];
byte a[] = new byte[256];
int mapsize = icm.getMapSize();
icm.getReds(r);
icm.getGreens(g);
icm.getBlues(b);
if (opaque) {
icm.getAlphas(a);
for (int i = 0; i < mapsize; i++) {
int rgb = filterRGB(icm.getRGB(i), brighter, percent);
a[i] = (byte) (rgb >> 24);
r[i] = (byte) (rgb >> 16);
g[i] = (byte) (rgb >> 8);
b[i] = (byte) (rgb >> 0);
}
}
return new IndexColorModel(icm.getPixelSize(), mapsize, r, g, b, a);
}
/**
* Define the ranges of varying highlight for the button.
* ranges is an array of 8 values which split up a scanline into
* 7 different regions of highlighting effect:
*
* ranges[0-1] = area outside of left edge of button
* ranges[1-2] = area inside UpperLeft highlight region left of center
* ranges[2-3] = area requiring custom highlighting left of center
* ranges[3-4] = area inside center of button
* ranges[4-5] = area requiring custom highlighting right of center
* ranges[5-6] = area inside LowerRight highlight region right of center
* ranges[6-7] = area outside of right edge of button
*
* Note that ranges[0-1] and ranges[6-7] are empty where the edges of
* the button touch the left and right edges of the image (everywhere
* on a square button) and ranges[2-3] and ranges[4-5] are only nonempty
* in those regions where the UpperLeft highlighting has leaked over
* the "top" of the button onto parts of its right edge or where the
* LowerRight highlighting has leaked under the "bottom" of the button
* onto parts of its left edge (can't happen on square buttons, happens
* occasionally on round buttons).
*/
public void buttonRanges(int y, int ranges[]) {
ranges[0] = ranges[1] = 0;
if (y < border) {
ranges[2] = ranges[3] = ranges[4] = ranges[5] = width - y;
} else if (y > height - border) {
ranges[2] = ranges[3] = ranges[4] = ranges[5] = height - y;
} else {
ranges[2] = ranges[3] = border;
ranges[4] = ranges[5] = width - border;
}
ranges[6] = ranges[7] = width;
}
public void setPixels(int x, int y, int w, int h,
ColorModel model, byte pixels[], int off,
int scansize) {
if (model == origbuttonmodel) {
int ranges[] = new int[8];
int x2 = x + w;
for (int cy = y; cy < y + h; cy++) {
buttonRanges(cy, ranges);
for (int i = 0; i < 7; i++) {
if (x2 > ranges[i] && x < ranges[i+1]) {
int cx1 = Math.max(x, ranges[i]);
int cx2 = Math.min(x2, ranges[i+1]);
if (models[i] == null) {
super.setPixels(cx1, cy, cx2 - cx1, 1,
model, pixels,
off + (cx1 - x), scansize);
} else {
if (cx1 < cx2) {
consumer.setPixels(cx1, cy, cx2 - cx1, 1,
models[i], pixels,
off + (cx1 - x), scansize);
}
}
}
}
off += scansize;
}
} else {
super.setPixels(x, y, w, h, model, pixels, off, scansize);
}
}
public int filterRGB(int x, int y, int rgb) {
boolean brighter;
int percent;
if ((x < border && y < height - x) || (y < border && x < width - y)) {
brighter = !pressed;
percent = defpercent;
} else if (x >= width - border || y >= height - border) {
brighter = pressed;
percent = defpercent;
} else if (pressed) {
brighter = false;
percent = defpercent / 2;
} else {
return rgb & 0x00ffffff;
}
return filterRGB(rgb, brighter, percent);
}
public int filterRGB(int rgb, boolean brighter, int percent) {
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb >> 0) & 0xff;
if (brighter) {
r = (255 - ((255 - r) * (100 - percent) / 100));
g = (255 - ((255 - g) * (100 - percent) / 100));
b = (255 - ((255 - b) * (100 - percent) / 100));
} else {
r = (r * (100 - percent) / 100);
g = (g * (100 - percent) / 100);
b = (b * (100 - percent) / 100);
}
if (r < 0) r = 0;
if (g < 0) g = 0;
if (b < 0) b = 0;
if (r > 255) r = 255;
if (g > 255) g = 255;
if (b > 255) b = 255;
return (rgb & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
}
}
class RoundButtonFilter extends ButtonFilter {
int Xcenter;
int Ycenter;
int Yradsq;
int innerW;
int innerH;
int Yrad2sq;
public RoundButtonFilter(boolean press, int p, int b, int w, int h) {
super(press, p, b, w, h);
Xcenter = w/2;
Ycenter = h/2;
Yradsq = h * h / 4;
innerW = w - border * 2;
innerH = h - border * 2;
Yrad2sq = innerH * innerH / 4;
}
public void buttonRanges(int y, int ranges[]) {
int yrel = Math.abs(Ycenter - y);
int xrel = (int) (Math.sqrt(Yradsq - yrel * yrel) * width / height);
int xslash = width - (y * width / height);
ranges[0] = 0;
ranges[1] = Xcenter - xrel;
ranges[6] = Xcenter + xrel;
ranges[7] = width;
if (y < border) {
ranges[2] = ranges[3] = ranges[4] = Xcenter;
ranges[5] = ranges[6];
} else if (y + border >= height) {
ranges[2] = ranges[1];
ranges[3] = ranges[4] = ranges[5] = Xcenter;
} else {
int xrel2 = (int) (Math.sqrt(Yrad2sq - yrel * yrel)
* innerW / innerH);
ranges[3] = Xcenter - xrel2;
ranges[4] = Xcenter + xrel2;
if (y < Ycenter) {
ranges[2] = ranges[3];
ranges[5] = ranges[6];
} else {
ranges[2] = ranges[1];
ranges[5] = ranges[4];
}
}
}
private int savedranges[];
private int savedy;
private synchronized int[] getRanges(int y) {
if (savedranges == null || savedy != y) {
if (savedranges == null) {
savedranges = new int[8];
}
buttonRanges(y, savedranges);
savedy = y;
}
return savedranges;
}
public int filterRGB(int x, int y, int rgb) {
boolean brighter;
int percent;
int i;
int ranges[] = getRanges(y);
for (i = 0; i < 7; i++) {
if (x >= ranges[i] && x < ranges[i+1]) {
break;
}
}
double angle;
switch (i) {
default:
case 0:
case 6:
return rgb & 0x00ffffff;
case 1:
brighter = !pressed;
percent = defpercent;
break;
case 5:
brighter = pressed;
percent = defpercent;
break;
case 2:
angle = Math.atan2(y - Ycenter, Xcenter - x);
percent = defpercent - ((int) (Math.cos(angle) * 2 * defpercent));
if (!pressed) {
percent = -percent;
}
if (percent == 0) {
return rgb;
} else if (percent < 0) {
percent = -percent;
brighter = false;
} else {
brighter = true;
}
break;
case 4:
angle = Math.atan2(Ycenter - y, x - Xcenter);
percent = defpercent - ((int) (Math.cos(angle) * 2 * defpercent));
if (pressed) {
percent = -percent;
}
if (percent == 0) {
return rgb;
} else if (percent < 0) {
percent = -percent;
brighter = false;
} else {
brighter = true;
}
break;
case 3:
if (!pressed) {
return rgb & 0x00ffffff;
}
brighter = false;
percent = defpercent;
break;
}
return filterRGB(rgb, brighter, percent);
}
}